package com.zlzxm.studentscreen.net.websocket;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;

import com.google.gson.Gson;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.exceptions.WebsocketNotConnectedException;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by zlz
 * on  11/18/20
 */
public class ClassRoomServer implements JWebSocketListener {


    public interface GetAddressCallback{

        void onGetAddress(String address);

    }

    private static final String TAG = "ClassRoomServer";

    private static final int RECONNECT_COUNT_QUICK = 3;

    private static final int RECONNECT_DURATION = 1000 * 10;

    private static final int COMMAND_RECONNECT = 10;



    //<editor-fold defaultState="collapsed" desc="单例">

    private static class ClassRoomServerHold{

        private static final ClassRoomServer CLASS_ROOM_SERVER_HOLD = new ClassRoomServer();

    }

    private ClassRoomServer() {

    }

    public static ClassRoomServer getInstance() {

        return ClassRoomServerHold.CLASS_ROOM_SERVER_HOLD;
    }

    // </editor-fold>

    //<editor-fold defaultState="collapsed" desc="变量">
    private Timer heartTimer;

    private Timer deviceTimer;

    private JWebSocketClient classSocketClient;

    private List<ClassRoomListener> classRoomListenerList;


    private Gson gson = new Gson();

    private String targetService;

    private  ReconnectThread myReconnectThread;
    private  Handler myReconnectHandle;

    private int reconectCount = 0;

    // </editor-fold>

    //<editor-fold defaultState="collapsed" desc="私有方法">

    private synchronized void initClient(String url){

        release();

        classSocketClient = new JWebSocketClient(URI.create(url));

        classSocketClient.setjWebSocketListener(this);

        targetService = url;
    }


    private synchronized int getCurrentPort(){

        if(isOpen()){

            return classSocketClient.getRemoteSocketAddress().getPort();
        }


        return 0;

    }


    private synchronized boolean isCurrentAddress(String address){

        if(TextUtils.isEmpty(address)){

            return false;

        }else {


            return  address.equals(targetService);

        }


    }

    private synchronized boolean isClientInit(){

        return  classSocketClient != null;
    }


    private synchronized  void startHeart(){

        stopHeart();

        heartTimer = new Timer();

        heartTimer.schedule(new MyHeartbeatTask(),3000,1000);
    }


    private synchronized  void stopHeart(){

        if(heartTimer != null){

            heartTimer.cancel();

            heartTimer = null;
        }

    }


    private synchronized void startSendDeviceInfo(){

        stopSendDeviceInfo();

        deviceTimer = new Timer();

        deviceTimer.schedule(new SendDeviceInfoTask(),10000,10000);
    }


    private synchronized  void stopSendDeviceInfo(){

        if(deviceTimer != null){
            deviceTimer.cancel();
            deviceTimer = null;
        }

    }

    private synchronized void release(){

        if(classSocketClient != null){

            classSocketClient.setjWebSocketListener(null);

            if(classSocketClient.isOpen()){

                classSocketClient.close();
            }
            classSocketClient = null;
            targetService = null;
            stopHeart();
            stopSendDeviceInfo();

        }


    }


    // </editor-fold>

    //<editor-fold defaultState="collapsed" desc="外部方法">


    public synchronized String getLocalIp(){

        if(isOpen()){

            return classSocketClient.getSocket().getLocalAddress().getHostAddress();
        }


        return null;

    }

    public synchronized void addClassRoomListener(ClassRoomListener classRoomListener) {
        Log.e(TAG,"addClassRoomListener");
        if(classRoomListenerList == null){
            classRoomListenerList = new ArrayList<>();
        }

        this.classRoomListenerList.add(classRoomListener);
    }

    public synchronized  void removeClassRoomListener(ClassRoomListener classRoomListener) {
        Log.e(TAG,"removeClassRoomListener");
        if(classRoomListenerList == null){
            return;
        }

        this.classRoomListenerList.remove(classRoomListener);
    }

    public synchronized void getCurrentServer(GetAddressCallback callback){

        if(callback!=null) {

            if (isOpen()) {

                new Thread(new Runnable() {
                    @Override
                    public void run() {

                        String address = classSocketClient.getRemoteSocketAddress().getHostName();

                        callback.onGetAddress(address);

                    }
                }).start();

            }

        }


    }


    public synchronized String getCurrentServer( ){


        if (!TextUtils.isEmpty(targetService)) {

            return targetService;

        }

        return null;
    }


    public synchronized void connect(String url) {
        Log.e(TAG,"开始连接："+url);

        if (TextUtils.isEmpty(url)) {

            return;
        }

        if (isClientInit()) {

            quitReconnectThread();

            if (isCurrentAddress(url)) {
                Log.e(TAG, "两次相同地址");
                //如果是相同地址 重新连接
                if (classSocketClient.isClosed() || classSocketClient.isClosing()) {

                    classSocketClient.reconnect();

                }
                return;

            }

        }

        initClient(url);

        classSocketClient.connect();

    }


    public synchronized  void startReconnect( ){

        startReconnect(classSocketClient);
    }

    public synchronized  void startReconnect(JWebSocketClient jWebSocketClient){

        if(myReconnectThread == null){

            reconectCount = 0 ;

            myReconnectThread = new ReconnectThread("reConnect");
            myReconnectThread.start();
            myReconnectHandle = new ReconnectHandle(myReconnectThread.getLooper(),jWebSocketClient);
        }

        if(myReconnectThread != null || myReconnectHandle != null){
            android.os.Message message  = android.os.Message.obtain();
            message.what = COMMAND_RECONNECT;

            if(reconectCount >= RECONNECT_COUNT_QUICK) {

                myReconnectHandle.sendMessageDelayed(message,RECONNECT_DURATION);

            }else {

                myReconnectHandle.sendMessage(message);
            }

            reconectCount ++;
        }

    }

    public synchronized void quitReconnectThread(){

        if(myReconnectThread != null){

            myReconnectThread.quit();
            myReconnectThread = null;
            myReconnectHandle = null;
        }

        reconectCount = 0;


    }


    public synchronized  void close(){

        if(isClientInit()){

            if(classSocketClient.isOpen()){

                classSocketClient.close();
            }

        }

    }


    public   void send(String text){

        if(isOpen()){

            try {
                classSocketClient.send(text);

            }catch (WebsocketNotConnectedException e){
                e.printStackTrace();

            }
        }

    }

    public  void send(ByteBuffer byteBuffer){

        if(isOpen()){

            try {

                classSocketClient.send(byteBuffer);

            }catch (WebsocketNotConnectedException e){

            }

        }

    }


    public  void send(byte[] data){

        if(isOpen()){

            classSocketClient.send(data);
        }

    }



    public synchronized boolean isOpen(){

        if(!isClientInit()){

            return false;
        }
        return classSocketClient.isOpen();

    }



    // </editor-fold>

    //<editor-fold defaultState="collapsed" desc="实现">
    @Override
    public void onOpen(ServerHandshake handshakeData) {
        quitReconnectThread();
        startHeart();
        startSendDeviceInfo();
        if(classRoomListenerList != null && classRoomListenerList.size() > 0){

            for (ClassRoomListener classRoomListener : classRoomListenerList) {

                classRoomListener.onWebSocketOpen(handshakeData);
            }

        }

    }

    @Override
    public void onMessage(String msg) {
        if(classRoomListenerList != null && classRoomListenerList.size()>0) {

            for (ClassRoomListener classRoomListener : classRoomListenerList) {

                classRoomListener.onMessage(msg);

            }
        }
    }


    @Override
    public void onClose(int code, String reason, boolean remote) {
        stopHeart();
        stopSendDeviceInfo();
        if(code != ErrorCode.CLOSE_NORMAL) {

            startReconnect(classSocketClient);
        }
        if(classRoomListenerList != null && classRoomListenerList.size() > 0){

            for (ClassRoomListener classRoomListener : classRoomListenerList) {

                classRoomListener.onWebSocketClose(code,reason,remote);
            }

        }
    }

    @Override
    public void onError(Exception ex) {
        if(classRoomListenerList != null && classRoomListenerList.size() > 0){

            for (ClassRoomListener classRoomListener : classRoomListenerList) {

                classRoomListener.onWebSocketError(ex);
            }

        }
    }
// </editor-fold>

    class MyHeartbeatTask extends TimerTask {

        @Override
        public void run() {

            if (isOpen()) {

                send("ping");

            } else {

                Log.d(TAG, "停止发送心跳包");

                heartTimer = null;

                cancel();

            }

        }

    }

    class SendDeviceInfoTask extends TimerTask {

        public  String TAG = "SendDeviceInfoTask";

        @Override
        public void run() {

            if (isOpen()) {



            } else {

                Log.d(TAG, "停止发送设备信息");

                deviceTimer = null;

                cancel();

            }

        }

    }


    static class ReconnectThread extends HandlerThread{

        public ReconnectThread(String name) {
            super(name);
        }
    }

    class ReconnectHandle extends Handler{

        private  WebSocketClient client;

        public ReconnectHandle(@NonNull Looper looper, WebSocketClient webSocketClient) {
            super(looper);
            this.client = webSocketClient;
        }

        @Override
        public void handleMessage(@NonNull android.os.Message msg) {
            super.handleMessage(msg);

            switch (msg.what){

                case  COMMAND_RECONNECT:
                    if(classSocketClient == client){

                        if(!client.isOpen()){
                            client.reconnect();

                        }else {
                            //任务超出任务次数 应该关闭重连任务
                            quitReconnectThread();

                        }


                    }else {
                        //不是同一个socket应该关闭重连任务
                        quitReconnectThread();
                    }

                    break;


                default:
                    //应该关闭重连任务
                    quitReconnectThread();
                    break;

            }

        }
    }



}
